﻿/*
 Copyright 2015 - 2015 SPrediction
 ConePrediction.cs is part of SPrediction
 
 SPrediction is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 SPrediction is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with SPrediction. If not, see <http://www.gnu.org/licenses/>.
*/

using System.Collections.Generic;
using System.Linq;
using EloBuddy;
//using EloBuddy.SDK;
using LeagueSharp.Common;
using SharpDX;

namespace SPrediction
{
    /// <summary>
    ///     Cone prediction class
    /// </summary>
    public static class ConePrediction
    {
        /// <summary>
        ///     Gets Prediction result
        /// </summary>
        /// <param name="input">Neccesary inputs for prediction calculations</param>
        /// <returns>Prediction result as <see cref="Prediction.Result" /></returns>
        public static Prediction.Result GetPrediction(Prediction.Input input)
        {
            return GetPrediction(input.Target, input.SpellWidth, input.SpellDelay, input.SpellMissileSpeed,
                input.SpellRange, input.SpellCollisionable, input.Path, input.AvgReactionTime, input.LastMovChangeTime,
                input.AvgPathLenght, input.LastAngleDiff, input.From.LSTo2D(), input.RangeCheckFrom.LSTo2D());
        }

        /// <summary>
        ///     Gets Prediction result
        /// </summary>
        /// <param name="target">Target for spell</param>
        /// <param name="width">Spell width</param>
        /// <param name="delay">Spell delay</param>
        /// <param name="missileSpeed">Spell missile speed</param>
        /// <param name="range">Spell range</param>
        /// <param name="collisionable">Spell collisionable</param>
        /// <param name="type">Spell skillshot type</param>
        /// <param name="from">Spell casted position</param>
        /// <returns>Prediction result as <see cref="Prediction.Result" /></returns>
        public static Prediction.Result GetPrediction(AIHeroClient target, float width, float delay, float missileSpeed,
            float range, bool collisionable)
        {
            return GetPrediction(target, width, delay, missileSpeed, range, collisionable, target.GetWaypoints(),
                target.AvgMovChangeTime(), target.LastMovChangeTime(), target.AvgPathLenght(), target.LastAngleDiff(),
                ObjectManager.Player.ServerPosition.LSTo2D(), ObjectManager.Player.ServerPosition.LSTo2D());
        }

        /// <summary>
        ///     Gets Prediction result
        /// </summary>
        /// <param name="target">Target for spell</param>
        /// <param name="width">Spell width</param>
        /// <param name="delay">Spell delay</param>
        /// <param name="missileSpeed">Spell missile speed</param>
        /// <param name="range">Spell range</param>
        /// <param name="collisionable">Spell collisionable</param>
        /// <param name="type">Spell skillshot type</param>
        /// <param name="path">Waypoints of target</param>
        /// <param name="avgt">Average reaction time (in ms)</param>
        /// <param name="movt">Passed time from last movement change (in ms)</param>
        /// <param name="avgp">Average Path Lenght</param>
        /// <param name="from">Spell casted position</param>
        /// <param name="rangeCheckFrom"></param>
        /// <returns>Prediction result as <see cref="Prediction.Result" /></returns>
        public static Prediction.Result GetPrediction(Obj_AI_Base target, float width, float delay, float missileSpeed,
            float range, bool collisionable, List<Vector2> path, float avgt, float movt, float avgp, float anglediff,
            Vector2 from, Vector2 rangeCheckFrom)
        {
            return Prediction.GetPrediction(target, width, delay, missileSpeed, range, collisionable,
                SkillshotType.SkillshotCone, path, avgt, movt, avgp, anglediff, from, rangeCheckFrom);
        }

        /// <summary>
        ///     Gets Aoe Prediction result
        /// </summary>
        /// <param name="width">Spell width</param>
        /// <param name="delay">Spell delay</param>
        /// <param name="missileSpeed">Spell missile speed</param>
        /// <param name="range">Spell range</param>
        /// <param name="from">Spell casted position</param>
        /// <param name="rangeCheckFrom"></param>
        /// <returns>Prediction result as <see cref="Prediction.AoeResult" /></returns>
        public static Prediction.AoeResult GetAoePrediction(float width, float delay, float missileSpeed, float range,
            Vector2 from, Vector2 rangeCheckFrom)
        {
            var result = new Prediction.AoeResult {HitCount = 0};
            var enemies =
                HeroManager.Enemies.Where(
                    p =>
                        p.LSIsValidTarget() &&
                        Prediction.GetFastUnitPosition(p, delay, 0, from).LSDistance(rangeCheckFrom) < range);

            foreach (var enemy in enemies)
            {
                var prediction = GetPrediction(enemy, width, delay, missileSpeed, range, false, enemy.GetWaypoints(),
                    enemy.AvgMovChangeTime(), enemy.LastMovChangeTime(), enemy.AvgPathLenght(), enemy.LastAngleDiff(),
                    from, rangeCheckFrom);
                if (prediction.HitChance > HitChance.Medium)
                {
                    var to = from + (prediction.CastPosition - from).LSNormalized()*range;
                    var spellHitBox = ClipperWrapper.DefineSector(from, to, width, range);
                    var collidedEnemies =
                        HeroManager.Enemies.AsParallel()
                            .Where(
                                p =>
                                    !spellHitBox.IsOutside(Prediction.GetFastUnitPosition(p, delay, missileSpeed, from)));
                    var collisionCount = collidedEnemies.Count();
                    if (collisionCount > result.HitCount)
                        result = prediction.ToAoeResult(collisionCount,
                            new Collision.Result(collidedEnemies.ToList<Obj_AI_Base>(), Collision.Flags.EnemyChampions));
                }
            }

            return result;
        }
    }
}